<?php

/**
 * 应用程序的公共控制器基础类
 *
 * 可以在这个类中添加方法来完成应用程序控制器共享的功能。
 */
abstract class Controller_Abstract extends QController_Abstract
{
    /**
     * 控制器动作要渲染的数据
     *
     * @var array
     */
    protected $_view = array();

    /**
     * 控制器要使用的视图类
     *
     * @var string
     */
    protected $_view_class = 'QView_Render_PHP';

    /**
     * 控制器要使用的视图
     *
     * @var string
     */
    protected $_viewname = null;

    /**
     * 控制器所属的应用程序
     *
     * @var CommunityApp
     */
    protected $_app;
    
    /**
     * 我定义的一周期的时间 7 * 24 * 3600
     *
     * $var int
     */
    protected $cycleLen = 604800;

    /**
     * 构造函数
     */
    function __construct($app)
    {
        parent::__construct();
        $this->_app = $app;
    }
    
    /**
     * 对表单的数据进行验证，返回验证的结果
     *
     *
     * $fd的格式为： array('name'=> 'xombat', 
     * 						'email' => 'xombat@gmail.com',
     * 						'sex' => 'male');
     * 
     * $rules的格式举例： array('name'=>array(array('not_null'), array('between', 6,32)),
     * 								'email'=>array(array('not_empty'), array('is_email'))
     * 	);
     * 
     * $rulesMsg 格式举例： array('name'=> array('not_null'=>'内容不能为空', 'between'=> '字符应该在xx范围内'),
     * 								'email' => array('is_email'=> '不是邮箱格式')
     * );
     * 返回的$errMsg结果为：
     * $errMsg = array(
     * 			'name' => '名字不能为空',
     * 			'email' => '请输入邮箱，邮箱格式为：witpns@gmail.com'
     * );
     * @param array $fd 表单数据
     * @param array $rules
     * @param array $rulesMsg
     * @param array $errMsg
     * 
     * @return bool 验证结果,验证没有问题，返回true,有问题返回false
     */
    function formValidate($fd, $rules, $rulesMsg, & $errMsg){
    	$ret = true;
    	if(!is_array($errMsg)){
    		$errMsg = array();
    	}
    	foreach($rules as $name=>$rule){
    		if(!isset($fd[$name])){
    			throw new InvalidArgumentException('没有为这个表单数据'+ $name);
    		}
    		$failed[$name] = array();
    		$ret = $ret && QValidator::validateBatch($fd[$name], $rule, true, $failed[$name]);
    		foreach($failed[$name] as $f){
    			if(isset($rulesMsg[$name]) && isset($rulesMsg[$name][$f])){
    				$errMsg[$name][] = $rulesMsg[$name][$f];
    			}else{
    				throw new Exception("没有为这个验证规则指定错误信息:$name, $f");
    			}
    		}
    	}
    	if ($ret && empty($errMsg)){
    		return true;
    	}else{
    		return false;
    	}
    }
    
	/**
	 * 返回某交易周期的交易评论起始时间
	 * 当参数为空的时候，则使用当前时间
	 *
	 * @return array
	 */
	function cycleFromTo($time = NULL){
		if($time == NULL){
			$time = time();
		}
		$time = intval($time);
		$now = time();
		
		if ($time > $now){
			$time = $now;
		}
		
		$offset = intval(($now - $time)/$this->cycleLen);
		$time = $now - $offset * $this->cycleLen;
		$to = strtotime(date("Y-m-d", $time + 24 * 3600));
		$from = $to - $this->cycleLen;
		
		return array("from" => $from, "to" => $to);
	}
	
	/**
	 * 返回的是当天的时间，不再考虑开市闭市时间问题
	 * 
	 * @return string
	 */
	function today(){
		$time = time();
		return date("Y-m-d", $time);
	}
	
	/**
	 * 上一个交易周期（周期是我定的，会经常变化）
	 *
	 * @param string $date
	 */
	function lastCycle($date = NULL){
		if($date == NULL){
			$date = $this->today();
		}
		$time = strtotime($date);
		$time = $time - $this->cycleLen;
		return date("Y-m-d", $time);
	}
	
	
	/**
	 * 下一个交易周期（周期是我定的，会经常变化）
	 *
	 * @param string
	 */
	function nextCycle($date = NULL){
		if($date == NULL){
			$date = $this->today();
		}
		
		$time = strtotime($date);
		$time = $time + $this->cycleLen;
		return date("Y-m-d", $time);
	}
	
	
    /**
     * 执行指定的动作
     *
     * @return mixed
     */
    function execute($action_name, array $args = array())
    {
        $action_method = "action{$action_name}";

        // 执行指定的动作方法
        $this->_before_execute();

        #IFDEF DBEUG
        QLog::log('EXECUTE ACTION: '. get_class($this) . '::' . $action_method . '()', QLog::DEBUG);
        #ENDIF

        $response = call_user_func_array(array($this, $action_method), $args);
        $this->_after_execute($response);

        if (is_null($response) && is_array($this->_view))
        {
            // 如果动作没有返回值，并且 $this->view 不为 null，
            // 则假定动作要通过 $this->view 输出数据
            $config = array('view_dir' => $this->_getViewDir());
            $response = new $this->_view_class($config);
            $response->setViewname($this->_getViewName())->assign($this->_view);
            $this->_before_render($response);
        }
        elseif ($response instanceof $this->_view_class)
        {
            $response->assign($this->_view);
            $this->_before_render($response);
        }

        return $response;
    }
    
    /**
     * 指定的控制器动作未定义时调用
     *
     * @param string $action_name
     */
    function _on_action_not_defined($action_name)
    {
    }

    /**
     * 执行控制器动作之前调用
     */
    protected function _before_execute()
    {
    }

    /**
     * 执行控制器动作之后调用
     *
     * @param mixed $response
     */
    protected function _after_execute(& $response)
    {
    }

    /**
     * 渲染之前调用
     *
     * @param QView_Render_PHP
     */
    protected function _before_render($response)
    {
    }

    /**
     * 准备视图目录
     *
     * @return array
     */
    protected function _getViewDir()
    {
        if ($this->_context->module_name)
        {
            $dir = Q::ini('app_config/MODULE_DIR') . "/{$this->_context->module_name}/view";
        }
        else
        {
            $dir = Q::ini('app_config/APP_DIR') . '/view';
        }

        if ($this->_context->namespace)
        {
            $dir .= "/{$this->_context->namespace}";
        }
        return $dir;
    }

    /**
     * 确定要使用的视图
     *
     * @return string
     */
    protected function _getViewName()
    {
        if ($this->_viewname === false)
        {
            return false;
        }
        $viewname = empty($this->_viewname) ? $this->_context->action_name : $this->_viewname;
        return strtolower("{$this->_context->controller_name}/{$viewname}");
    }

    /**
     * 显示一个提示页面，然后重定向浏览器到新地址
     *
     * @param string $caption
     * @param string $message
     * @param string $url
     * @param int $delay
     * @param string $script
     *
     * @return QView_Render_PHP
     */
    protected function _redirectMessage($caption, $message, $url, $delay = 5, $script = '')
    {
        $config = array('view_dir' => $this->_getViewDir());
        $response = new $this->_view_class($config);
        $response->setViewname('redirect_message');
        $response->assign(array(
            'message_caption'   => $caption,
            'message_body'      => $message,
            'redirect_url'      => $url,
            'redirect_delay'    => $delay,
            'hidden_script'     => $script,
        ));

        return $response;
    }
}

